/*
*Copyright 2021-2023 NERCIS
*
*Licensed under the Apache License, Version 2.0 (the "License");
*you may not use this file except in compliance with the License.
*You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing, software
*distributed under the License is distributed on an "AS IS" BASIS,
*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*See the License for the specific language governing permissions and
*limitations under the License.
*/

package cn.ac.nercis.pes.service.project;

import cn.ac.nercis.pes.common.utils.DataUtils;
import cn.ac.nercis.pes.common.constant.evaluation.EvaluationModule;
import cn.ac.nercis.pes.common.constant.project.FinishState;
import cn.ac.nercis.pes.common.constant.project.SystemState;
import cn.ac.nercis.pes.model.dto.common.Result;
import cn.ac.nercis.pes.model.dto.common.ResultCode;
import cn.ac.nercis.pes.model.dto.project.SystemProcessDTO;
import cn.ac.nercis.pes.repository.dal.project.SystemProcessRepository;
import cn.ac.nercis.pes.repository.mapper.project.SystemMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 系统测评进度服务
 * @author zpy
 * @version 1.0.0
 */
@Slf4j
@Service
public class SystemProcessService {
    private final SystemProcessRepository processRepository;

    @Autowired
    public SystemProcessService(SystemProcessRepository systemProcessRepository) {
        this.processRepository = systemProcessRepository;
    }

    public List<SystemProcessDTO> findSystemProcess(String systemId, SystemState state) {
        return this.processRepository.findAllBySystemIdAndState(systemId, state)
                .stream()
                .map(SystemMapper.INSTANCE::toSystemProcessDTO)
                .collect(Collectors.toList());
    }

    public List<SystemProcessDTO> findTargetConfirmProcess(String systemId) {
        return this.findSystemProcess(systemId, SystemState.PLANNING, EvaluationModule.findTargetConfirmModules());
    }

    public List<SystemProcessDTO> findContentConfirmProcess(String systemId) {
        return this.findSystemProcess(systemId, SystemState.PLANNING, EvaluationModule.findContentConfirmModules());
    }

    public List<SystemProcessDTO> findEvaRequireProcess(String systemId) {
        return this.findSystemProcess(systemId, SystemState.PLANNING, EvaluationModule.findEvaRequireModules());
    }

    public List<SystemProcessDTO> findUnitEvalProcess(String systemId) {
        return this.findSystemProcess(systemId, SystemState.REPORT, EvaluationModule.findUnitEvalModules());
    }

    public List<SystemProcessDTO> findOverallEvalProcess(String systemId){
        return this.findSystemProcess(systemId, SystemState.REPORT, EvaluationModule.findOverallEvalModules());
    }

    public List<SystemProcessDTO> findRiskAnalysisProcess(String systemId){
        return this.findSystemProcess(systemId, SystemState.REPORT, EvaluationModule.findRiskAnalysisEvalModules());
    }

    public List<SystemProcessDTO> findOverallAppraiseProcess(String systemId){
        return this.findSystemProcess(systemId, SystemState.REPORT, EvaluationModule.findOverallAppraiseEvalModules());
    }

    public Result<SystemProcessDTO> setSystemProcess(SystemProcessDTO processDTO) {
        var entity = DataUtils.getFirst(this.processRepository.findBySystemIdAndStateAndName(processDTO.getSystemId(),
                processDTO.getState(), processDTO.getName()));
        if (Objects.isNull(entity)) {
            entity = SystemMapper.INSTANCE.toSystemProcessDO(processDTO);
            entity.setCreateTime(LocalDateTime.now());
        } else {
            entity.setFinishState(processDTO.getFinishState());
            entity.setModifyTime(LocalDateTime.now());
        }
        return Optional.of(entity)
                .map(processRepository::save)
                .map(SystemMapper.INSTANCE::toSystemProcessDTO)
                .map(Result::success)
                .orElse(Result.failed(ResultCode.FAIL));
    }

    public Result<SystemProcessDTO> setSystemProcess(String systemId, EvaluationModule module, FinishState finishState) {
        return this.setSystemProcess(SystemProcessDTO.builder()
                .systemId(systemId)
                .state(module.getState())
                .name(module.getName())
                .finishState(finishState)
                .build());
    }

    private List<SystemProcessDTO> findSystemProcess(String systemId, SystemState state, List<EvaluationModule> modules) {
        return this.processRepository.findAllBySystemIdAndState(systemId, state)
                .stream()
                .filter(sp -> modules.stream().anyMatch(em -> StringUtils.equals(sp.getName(), em.getName())))
                .map(SystemMapper.INSTANCE::toSystemProcessDTO)
                .collect(Collectors.toList());
    }
}